﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Moq;
using NUnit.Framework;
using SportsStore.Model;
using SportsStore.Repository.Interfaces;
using SportsStore.Services;
using SportsStore.ServicesInterfaces;

namespace SportsStore.UnitTests.Services
{
  [TestFixture]
  public class CartItemServiceTest
  {
    [SetUp]
    public void Setup()
    {
      _cartItemRepository = new Mock<ICartItemRepository>();
      _cartItemService = new CartItemService(_cartItemRepository.Object);
    }

    private ICartItemService _cartItemService;
    private Mock<ICartItemRepository> _cartItemRepository;
    int _itemCount = 0;

    [Test]
    public void GivenANewBasket_WhenIAskToAddAProductToTheBasket_TheProductIsAddedToMyBasket()
    {
      _cartItemRepository.Setup(p => p.GetCart(It.IsAny<int>(), It.IsAny<string>()));
      _cartItemService.AddItem(It.IsAny<int>(), It.IsAny<string>(), It.IsAny<int>());
      _cartItemRepository.Verify(c => c.Create(It.IsAny<CartItem>()), Times.Once());
    }

    [Test]
    public void GivenAnExistingBasket_WhenIAskToAddAProductToTheBasket_TheProductIsAddedToMyBasket()
    {
        _cartItemRepository.Setup(p => p.GetCart(It.IsAny<int>(), It.IsAny<string>())).Returns(new CartItem());
        _cartItemService.AddItem(It.IsAny<int>(), It.IsAny<string>(), It.IsAny<int>());
        _cartItemRepository.Verify(c => c.Update(It.IsAny<CartItem>()), Times.Once());
    }

    [Test]
    public void GivenANewBasket_WhenIAskToRemoveAProduct_TheProductIsNotRemovedFromMyBasket()
    {
      _cartItemRepository.Setup(p => p.GetCart(It.IsAny<int>(), It.IsAny<string>()));
      _itemCount = _cartItemService.RemoveItem(It.IsAny<int>(), It.IsAny<string>());
      _cartItemRepository.Verify(c => c.Create(It.IsAny<CartItem>()), Times.Never());
      _cartItemRepository.Verify(c => c.Update(It.IsAny<CartItem>()), Times.Never());

      Assert.That(_itemCount, Is.EqualTo(0));
    }

    [Test]
    public void GivenABasketWithAProductWithQuantityGreaterThanOne_WhenIAskToRemoveAProductFromTheBasket_TheProductIsRemovedFromMyBasket()
    {
      _cartItemRepository.Setup(p => p.GetCart(It.IsAny<int>(), It.IsAny<string>())).Returns(new CartItem() { Quantity = 3});
      _itemCount = _cartItemService.RemoveItem(It.IsAny<int>(), It.IsAny<string>());
      _cartItemRepository.Verify(c => c.Update(It.IsAny<CartItem>()), Times.Once());

      Assert.That(_itemCount, Is.EqualTo(2));
    }

    [Test]
    public void
      GivenABasketWithAProductWithQuantityOfOne_WhenIAskToRemoveAProductFromTheBasket_TheProductIsRemovedFromMyBasket()
    {
      _cartItemRepository.Setup(p => p.GetCart(It.IsAny<int>(), It.IsAny<string>())).Returns(new CartItem() { Quantity = 1 });
      _itemCount = _cartItemService.RemoveItem(It.IsAny<int>(), It.IsAny<string>());
      _cartItemRepository.Verify(c => c.Delete(It.IsAny<CartItem>()), Times.Once());

      Assert.That(_itemCount, Is.EqualTo(0));
    }

    [Test]
    public void GivenAValidShoppingCartId_WhenIAskToComputeTheTotalValue_TheTotalValueIsReturned()
    {
      _cartItemRepository.Setup(p => p.GetTotal(It.IsAny<string>())).Returns(10M);
      var totalValue = _cartItemService.ComputeTotalValue(It.IsAny<string>());
      _cartItemRepository.Verify(c => c.GetTotal(It.IsAny<string>()), Times.Once());

      Assert.That(totalValue, Is.EqualTo(10M));
    }

    [Test]
    public void GivenAValidBasket_WhenIAskToClearTheBasket_TheBasketIsCleared()
    {
      _cartItemRepository.Setup(p => p.GetCart(It.IsAny<string>()))
                         .Returns(new List<CartItem>
                           {
                             new CartItem() {Id = 1},
                             new CartItem() {Id = 2},
                             new CartItem() {Id = 3}
                           });
      _cartItemService.ClearBasket(It.IsAny<string>());
      _cartItemRepository.Verify(c => c.Delete(It.IsAny<CartItem>()), Times.Exactly(3));
    }
  }
}
